/*
*    l3qd - Light, light, lightweight queue
*    Copyright (C) 2024  Marcus Pedersén marcus@marcux.org
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package list

import (
	"encoding/json"
	"fmt"
	"github.com/spf13/cobra"
	"notabug.org/marcux/l3q/internal/client"
	"notabug.org/marcux/l3q/internal/common"
	"os"
	"strconv"
	"strings"
)

var listTaskCmdFlagVerbose bool

var listTaskCmd = &cobra.Command{
	Use:   "task JOBID",
	Args:  cobra.ExactArgs(1),
	Short: "List all tasks for specified job",
	Long: `Description:
  Lists all tasks that belong to specific job in l3q.
  JOBID is required as a positional argument.`,
	Run: func(cmd *cobra.Command, args []string) {
		jobid, err := strconv.Atoi(args[0])

		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to parse JOBID: %s, as integer.\nJOBID is required to be a positive integer.\nTry -h or --help for help.\n",
				args[0])

			if listTaskCmdFlagVerbose {
				fmt.Fprintf(os.Stderr, "%s\n", err)
			}

			os.Exit(1)
		}

		if jobid <= 0 {
			fmt.Fprintf(os.Stderr, "JOBID is required to be a positive integer.\nTry -h or --help for help.\n")
			os.Exit(1)
		}

		printTask(jobid)
	},
}

func printTask(jobid int) {
	jobs := []common.Job{}
	urlSuffix := fmt.Sprintf("/job?id=%d&tasks", jobid)

	jsonBytes := client.UrlGet(urlSuffix, listTaskCmdFlagVerbose)
	err := json.Unmarshal(jsonBytes, &jobs)
	if err != nil {
		if listTaskCmdFlagVerbose {
			fmt.Fprintf(os.Stderr, "Failed to decode json string to struct\n%s\n.", err)
		} else {
			fmt.Fprintf(os.Stderr, "Failed to decode json string.\n")
		}
		os.Exit(1)
	}

	if len(jobs) > 1 {
		fmt.Fprintf(os.Stderr, "Wrong response from daemon.\nMore than one job in response from l3qd daemon.")
		os.Exit(1)
	}

	var headline, line string

	if jobs[0].Type == common.JobTypeSequence {
		headline = strings.Repeat("=", 140)
		line = strings.Repeat("-", 140)
	} else {
		headline = strings.Repeat("=", 147)
		line = strings.Repeat("-", 147)
	}

	fmt.Println(headline)

	if jobs[0].Type == common.JobTypeSequence {
		fmt.Printf("| %s |         %s         |        %s        |         %s         |      %s       | %s | %s\n",
			"Taskid", "Node", "Start", "End", "Run time", "Exit code", "Command")
	} else {
		fmt.Printf("| %s |         %s         | %s |        %s        |         %s         |      %s       | %s | %s\n",
			"Taskid", "Node", "Cores", "Start", "End", "Run time", "Exit code", "Command")
	}

	fmt.Println(headline)

	if len(jobs) == 1 {
		for _, t := range jobs[0].Tasks {
			nodename := "-"
			starttime := "-"
			endtime := "-"
			runtime := "-"

			if t.NodeID > 0 {
				node := []common.Node{}
				urlNode := fmt.Sprintf("/node?id=%d", t.NodeID)

				nodeBytes := client.UrlGet(urlNode, listTaskCmdFlagVerbose)
				err := json.Unmarshal(nodeBytes, &node)
				if err != nil {
					if listTaskCmdFlagVerbose {
						fmt.Fprintf(os.Stderr, "Failed to decode json string to Node struct\n%s\n.", err)
					} else {
						fmt.Fprintf(os.Stderr, "Failed to decode json string.\n")
					}
					os.Exit(1)
				}

				if len(node) != 1 {
					fmt.Fprintf(os.Stderr, "Failed to get node id: %d for task id: %d\n",
						t.NodeID, t.Id)
					os.Exit(1)
				}

				if len(node[0].Name) > 20 {
					nodename = node[0].Name[:20]
				} else {
					nodename = node[0].Name
				}
			}

			if len(t.StartTime) > 0 {
				starttime = t.StartTime
			}

			if len(t.EndTime) > 0 {
				endtime = t.EndTime
			}

			if len(t.RunTime) > 0 {
				runtime = t.RunTime
			}

			if jobs[0].Type == common.JobTypeSequence {
				fmt.Printf("| %6d | %20s | %19s | %19s | %19s | %9d | %s\n",
					t.Id, nodename, starttime, endtime, runtime, t.ExitCode, t.Command)
			} else {
				fmt.Printf("| %6d | %20s | %5d | %19s | %19s | %19s | %9d | %s\n",
					t.Id, nodename, t.Cores, starttime, endtime, runtime, t.ExitCode, t.Command)
			}

			fmt.Println(line)
		}
	}
}

func init() {
	listTaskCmd.Flags().BoolVarP(&listTaskCmdFlagVerbose, "verbose", "v", false, "Print verbose output")
}
